package wdevent

import (
	"errors"
	"time"
)

type Entity struct {
	maxCycle int
	timeout  time.Duration
	globals  []EventHandle
	middle   map[string][]EventHandle
	events   map[string][]EventHandle
}

func NewEventEntity() *Entity {
	return &Entity{
		maxCycle: 99,
		timeout:  0,
		globals:  make([]EventHandle, 0),
		middle:   make(map[string][]EventHandle),
		events:   make(map[string][]EventHandle),
	}
}
func (e *Entity) SetMaxCycle(max int) *Entity {
	e.maxCycle = max
	return e
}
func (e *Entity) SetTimeout(to time.Duration) *Entity {
	e.timeout = to
	return e
}
func (e *Entity) RegisterEvent(s string, handle EventHandle) *Entity {
	if list, ok := e.events[s]; ok {
		e.events[s] = append(list, handle)
	} else {
		e.events[s] = make([]EventHandle, 0)
		e.events[s] = append(e.events[s], handle)
	}
	return e
}
func (e *Entity) RegisterMiddle(s string, handle EventHandle) *Entity {
	if list, ok := e.middle[s]; ok {
		e.middle[s] = append(list, handle)
	} else {
		e.middle[s] = make([]EventHandle, 0)
		e.middle[s] = append(e.middle[s], handle)
	}
	return e
}
func (e *Entity) RegisterGlobal(handle EventHandle) *Entity {
	e.globals = append(e.globals, handle)
	return e
}
func (e *Entity) Dispatch(key string, ctx *Context) error {
	events, ok := e.events[key]
	if !ok {
		return errors.New(ErrorNotFoundEventFromCurrentKey.Error() + ":" + key)
	}
	middle := e.middle[key]
	if ctx == nil {
		ctx = NewContext()
	}
	if ctx.timeout == 0 {
		ctx.SetTimeout(e.timeout)
	}
	if ctx.maxCycle == 0 {
		ctx.SetMaxCycle(e.maxCycle)
	}
	ctx.setContextByEventHandle(e.globals, middle, events)
	if ctx.timeout != 0 {
		return Timeout(ctx.timeout, func() error {
			return ctx.Next()
		})
	}
	return ctx.Next()
}
